package com.runa.monitor.platinterface.netservice.equipment.dtu;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.comm.dto.Node;
import com.runa.monitor.comm.dto.newComm.AsynResult;
import com.runa.monitor.platinterface.backwork.impl.RccTaskFunction;
import com.runa.monitor.platinterface.backwork.impl.SubEquWriteTaskFunction;
import com.runa.monitor.platinterface.mqtt.MqttUtil;
import com.runa.monitor.platinterface.backwork.function.TaskFunction;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.persistence.DateUtil;
import com.runa.persistence.util.LogUtil;
import com.runa.protocol.dto.ModbusResponseData;
import com.runa.protocol.dto.ResponseContent;
import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.runa.RunaConcenAffirmDeny;
import com.runa.rccprotocol.netservice.dtu.ModbusRtuResponse;
import com.runa.rccprotocol.netservice.modbus.ModbusRequest;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * 2024/9/2 20:23
 * zhangYB
 */
@Slf4j
public class DtuTaskFunction implements TaskFunction<Object, ResponseContent, String> {

    protected TaskFunction function;

    protected Integer count;

    protected Node node;

    protected List<ModbusRequest> requests = new ArrayList<>();

    protected List<ModbusRtuResponse> responses = new ArrayList<>();
    private boolean exceptionFinished = false;
    private boolean read = true;

    public DtuTaskFunction(TaskFunction function, Node node, Integer count, boolean read) {
        this(function, node, count);
        this.read = read;
    }

    public DtuTaskFunction(TaskFunction function, Node node, Integer count) {
        this(function, count);
        this.node = node;
    }

    public DtuTaskFunction(TaskFunction function, Integer count) {
        this.function = function;
        this.count = count;
    }

    public void addRequest(ModbusRequest request) {
        requests.add(request);
    }

    public void addResponse(ModbusRtuResponse response) {
        if (requests.size() == responses.size() + 1) {
            ModbusResponseData modbusResponse = response.getModbusResponse();
            ModbusRequest modbusRequest = getLastRequest();
            if (modbusResponse.getSlaveId() != modbusRequest.getSlaveId()) {
                log.debug("{} 请求与响应设备地址不同", getSerial());
                return;
            }
            if (modbusResponse.getCount() != modbusRequest.getRegisterCount()*2) {
                log.debug("{} 请求与响应设备寄存器个数不同", getSerial());
                return;
            }
            response.setModbusRequest(modbusRequest);
            responses.add(response);
        }
    }

    public ModbusRequest getLastRequest() {
        if (requests.isEmpty()) {
            return null;
        }
        return requests.get(requests.size() - 1);
    }

    public void finish() {
        if (read) {
            ResponseContent responseContent = new ResponseContent();
            for (int i = 0; i < count; i++) {
                ModbusRtuResponse modbusRtuResponse = responses.get(i);
                ModbusRequest modbusRequest = modbusRtuResponse.getModbusRequest();
                ModbusResponseData modbusResponse = modbusRtuResponse.getModbusResponse();
                log.debug("{} request data: {}", getSerial(), ByteUtil.byteToHexString(modbusRequest.getData()));
                log.debug("{} response data: {}", getSerial(), ByteUtil.byteToHexString(modbusResponse.getData()));
                responseContent.putAll(modbusRtuResponse.analysis());
            }
            log.debug("responseContent: {}", JSON.toJSONString(responseContent));
            ok(responseContent);
        } else {
            writeOk();
        }
    }

    public void writeOk() {
        if (function instanceof SubEquWriteTaskFunction) {
            LogUtil.info(getSerial(), "DtuTaskFunction.writeOk: {}", new RunaConcenAffirmDeny(true));
            function.doApply(CommStatus.OK, new RunaConcenAffirmDeny(true));
        }
    }

    public void ok(ResponseContent responseContent) {
        Object obj = responseContent.get("meterDate");
        if (null != obj) {
            String meterDate = String.valueOf(obj);
            responseContent.put("meterDate", DateUtil.noLineFormatToDate("20"+meterDate));
        }
        responseContent.put("readTime", new Date());
        if (null != node) {
            responseContent.setIndexNo(node.getIndex());
            responseContent.setId(node.getId());
            responseContent.setSerial(node.getSerial());
            responseContent.setModel(node.getModel());
        }
        doApply(CommStatus.OK, responseContent);
    }


    @Override
    public void doApply(CommStatus status, ResponseContent responseContent) {
        log.debug("{} DtuTaskFunction.doApply: {} {}", getSerial(), status, JSON.toJSONString(responseContent));
        LogUtil.info(getSerial(), "DtuTaskFunction.doApply: {}", status);
        if (!status.equals(CommStatus.OK)) {
            exceptionFinished = true;
        }
        function.doApply(status, responseContent);
    }

    @Override
    public void setStatus(Object o) {
    }

    @Override
    public String waitResult() {
        return null;
    }

    @Override
    public String getSerial() {
        return function.getSerial();
    }

    @Override
    public int getPriority() {
        return 0;
    }

    public boolean canRequest() {
        return requests.size() == responses.size();
    }

    public boolean isTailFrame() {
        log.debug("isTailFrame: {} {} {}", responses.size(), count, exceptionFinished);
        return responses.size() == count && !exceptionFinished;
    }


}
